using UnityEngine;
using static UnityEngine.Mathf;

// 定义一个静态类 FunctionLibrary，用于存放一系列数学函数，这些函数用于生成三维空间中的点（通常用于可视化或图形绘制）
public static class FunctionLibrary
{

	// 定义一个委托类型 Function，它接收三个 float 参数：u, v, t，返回一个 Vector3
	// 该委托用于描述一个“数学函数”，输入是二维或带时间的参数，输出是一个三维坐标点
	public delegate Vector3 Function(float u, float v, float t);

	// 定义一个枚举 FunctionName，表示当前支持的几种不同的函数类型
	public enum FunctionName
	{
		Wave,     // 波浪函数
		MultiWave, // 多重波浪叠加函数
		Ripple,   // 涟漪/水波扩散函数
		Sphere,   // 球体变形函数
		Torus     // 环面（甜甜圈形状）函数
	}

	// 静态数组，存储所有可用的函数，按照 FunctionName 枚举的顺序一一对应
	static Function[] functions = {
		Wave, MultiWave, Ripple, Sphere, Torus
	};

	// 根据传入的 FunctionName 枚举值，返回对应的函数委托
	public static Function GetFunction(FunctionName name)
	{
		return functions[(int)name]; // 将枚举转换为索引，取函数数组中对应的函数
	}

	// 返回当前函数的下一个函数（按枚举顺序循环，比如 Wave -> MultiWave -> ... -> Wave）
	public static FunctionName GetNextFunctionName(FunctionName name)
	{
		// 如果当前不是最后一个函数，就返回下一个；否则返回第一个（循环）
		return (int)name < functions.Length - 1 ? name + 1 : 0;
	}

	// 返回一个不同于当前函数的随机函数（避免连续两次显示同一个函数）
	public static FunctionName GetRandomFunctionNameOtherThan(FunctionName name)
	{
		// 在 1 到 functions.Length - 1 范围内随机选择一个函数（避免选到自己）
		var choice = (FunctionName)Random.Range(1, functions.Length);
		// 如果随机到的函数恰好就是当前函数，则返回第一个函数（0）作为替代
		return choice == name ? 0 : choice;
	}

	// ========================== 以下是具体的函数实现 ==========================

	// 函数1：Wave（基础波浪）
	// 输入：u, v 是平面上的坐标，t 是时间
	// 输出：一个在 u 方向不变，v 方向有正弦波动，z 方向也不变的点
	public static Vector3 Wave(float u, float v, float t)
	{
		Vector3 p;
		p.x = u; // x 坐标不变
		p.y = Sin(PI * (u + v + t)); // y 坐标根据 u, v 和时间 t 的组合进行正弦波动
		p.z = v; // z 坐标不变
		return p;
	}

	// 函数2：MultiWave（多重波浪叠加）
	// 多个不同频率和振幅的正弦波叠加，形成更复杂的波形
	public static Vector3 MultiWave(float u, float v, float t)
	{
		Vector3 p;
		p.x = u; // x 不变

		// y 坐标由多个正弦函数叠加而成，并最后做归一化处理
		p.y = Sin(PI * (u + 0.5f * t)); // 第一层波动
		p.y += 0.5f * Sin(2f * PI * (v + t)); // 第二层波动，频率更高
		p.y += Sin(PI * (u + v + 0.25f * t)); // 第三层波动，综合 u, v 和时间
		p.y *= 1f / 2.5f; // 所有波动叠加后缩小振幅，让整体不过于剧烈

		p.z = v; // z 不变
		return p;
	}

	// 函数3：Ripple（涟漪 / 水波效果）
	// 基于到中心点的距离产生一圈圈的波纹效果
	public static Vector3 Ripple(float u, float v, float t)
	{
		float d = Sqrt(u * u + v * v); // 计算 (u, v) 到原点 (0,0) 的距离
		Vector3 p;
		p.x = u; // x 不变

		// y 坐标是一个正弦波，频率与距离 d 和时间 t 相关，同时除以 (1 + 10d) 做衰减，形成涟漪效果
		p.y = Sin(PI * (4f * d - t));
		p.y /= 1f + 10f * d;

		p.z = v; // z 不变
		return p;
	}

	// 函数4：Sphere（球体）
	// 生成一个变形的球体表面上的点，球的半径会随时间轻微变化
	public static Vector3 Sphere(float u, float v, float t)
	{
		// 半径随时间轻微波动
		float r = 0.9f + 0.1f * Sin(PI * (6f * u + 4f * v + t));

		// 球坐标系中，先计算垂直方向的半径分量
		float s = r * Cos(0.5f * PI * v);

		Vector3 p;
		// 转换为笛卡尔坐标
		p.x = s * Sin(PI * u); // x 坐标
		p.y = r * Sin(0.5f * PI * v); // y 坐标（极径在竖直方向的分量）
		p.z = s * Cos(PI * u); // z 坐标

		return p;
	}

	// 函数5：Torus（环面，甜甜圈形状）
	// 生成一个环面表面的点，内外径都会随时间微调，形成动态效果
	public static Vector3 Torus(float u, float v, float t)
	{
		// 外环主半径 r1 会随时间波动
		float r1 = 0.7f + 0.1f * Sin(PI * (6f * u + 0.5f * t));
		// 内环小半径 r2 也会波动
		float r2 = 0.15f + 0.05f * Sin(PI * (8f * u + 4f * v + 2f * t));

		// 计算环面上点到中心的距离（外环半径 + 内环半径 * cos(v)）
		float s = r1 + r2 * Cos(PI * v);

		Vector3 p;
		p.x = s * Sin(PI * u); // x 坐标
		p.y = r2 * Sin(PI * v); // y 坐标（环的竖直方向）
		p.z = s * Cos(PI * u); // z 坐标

		return p;
	}

	// ========================== 函数过渡插值 ==========================

	// Morph 函数用于在两个不同的 Function 输出之间进行平滑插值过渡
	// 用于函数切换时的动画效果，让图形从一个形态平滑变化到另一个形态
	public static Vector3 Morph(
		float u, float v, float t,
		Function from, Function to, float progress
	)
	{
		// 使用 LerpUnclamped 对两个函数的结果进行线性插值
		// SmoothStep(0, 1, progress) 让过渡更自然（慢-快-慢）
		return Vector3.LerpUnclamped(
			from(u, v, t),     // 起始函数在该点的位置
			to(u, v, t),       // 目标函数在该点的位置
			SmoothStep(0f, 1f, progress) // 插值系数，经过 SmoothStep 处理更平滑
		);
	}
}